PC 4K Intro minify テクニック by よっしん
https://youtu.be/JsNNMjP46ys?si=JWlAHT9NyOZWsU_t
内容
(略)
4kの作り方
4kに特化した定番minifier
高い圧縮率を得るためTips
似たバイト値が近くにある
完全一致する長いバイト列がある
バイト値の種類が少ない
なので、実践として
なるべく既出の命令を使う
Crinklerが起動するまで
exeがメモリ上に展開される
_Import というcrinklerが自動的に付加する120バイトほどの処理を実行、 opengl32.dll や user32.dll 等のAPIアドレスを取得し、ユーザプログラムから使えるようにする
ユーザプログラムを実行、 _entrypoint というシンボルから開始
Crinklerの推奨オプション
/REPORT
/COMPMODE:SLOW
/HASHSIZE:300
/HASHTRIES:300
/ORDERTRIES:300
/UNSAFEIMPORT
/OVERRIDEALIGNMENTS
/UNALIGNCODE
/NOINITIALIZERS
/TINYIMPORT は非推奨。将来的なDLLのアップデートによりAPIアドレスを表すハッシュ値がコリジョンしやすい
人の手による温かみのあるminify
Shader MinifierとCrinklerを使ってがんばる
Crinklerの /REPORT オプションで吐き出されるHTMLファイルを見ながらがんばる
シェーダコードのminify tips
Shader Minifierは万能ではないので、手動でMinifyを行う
とはいえ、Crinklerで圧縮する場合、トリッキーな書き方をするより短く素直なコードを目指したほうが有利
関数オーバーロードを使おう
定義済みシンボルを使い回す
変数名の使用傾向を統一する。for文の i ・座標の p など
int 型を float 型に統一してみる
min(...min(...min(...))) は min(min(min(...)...)...) のほうが効率が良い
ネイティブコードのminify tips
なるべく短い命令を使う
レジスタの0クリアは XOR を使う
レジスタ値代入は2バイト使うが、レジスタ値交換は1バイトで済む
単純な命令の組み合わせで圧縮効率化
MOV を PUSH ・ POP で置き換えたり
レジスタの使用傾向を統一する
PUSH は毎回同じレジスタを使うとか
_entrypoint のレジスタ初期値をabuseする
ECX レジスタは初期値は必ず 0 が入っているなど
自力でAPIアドレスを取得するほうが有利なこともある
Win32 APIの戻り値を使う。EAXレジスタに1を返すAPIは貴重
pre push。関数呼び出し時の引数pushをあらかじめしておく
undocumentedなAPI使用をabuse。過去バージョンとの互換性のために残されている謎仕様
省略して良いAPIを探す